package com.changanw.tienchin.contract.service.impl;

import com.aspose.words.Document;
import com.aspose.words.PdfCompliance;
import com.aspose.words.PdfSaveOptions;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.changanw.tienchin.business.domain.Business;
import com.changanw.tienchin.business.service.IBusinessService;
import com.changanw.tienchin.common.constant.TienChinConstants;
import com.changanw.tienchin.common.core.domain.AjaxResult;
import com.changanw.tienchin.common.utils.SecurityUtils;
import com.changanw.tienchin.common.utils.sign.Base64;
import com.changanw.tienchin.contract.domain.Contract;
import com.changanw.tienchin.contract.domain.vo.ContractApproveInfo;
import com.changanw.tienchin.contract.domain.vo.ContractInfo;
import com.changanw.tienchin.contract.domain.vo.ContractSummary;
import com.changanw.tienchin.contract.mapper.ContractMapper;
import com.changanw.tienchin.contract.service.IContractService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.changanw.tienchin.course.domain.Course;
import com.changanw.tienchin.course.service.ICourseService;
import org.flowable.engine.HistoryService;
import org.flowable.engine.RuntimeService;
import org.flowable.engine.TaskService;
import org.flowable.engine.history.HistoricProcessInstance;
import org.flowable.engine.runtime.Execution;
import org.flowable.engine.runtime.ProcessInstance;
import org.flowable.task.api.Task;
import org.flowable.variable.api.history.HistoricVariableInstance;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.http.HttpServletRequest;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.UUID;

/**
 * <p>
 *  服务实现类
 * </p>
 *
 * @author changanw
 * @since 2023-12-12
 */
@Service
public class ContractServiceImpl extends ServiceImpl<ContractMapper, Contract> implements IContractService {
  @Autowired
  ContractMapper contractMapper;
  @Autowired
  IBusinessService businessService;
  @Autowired
  ICourseService courseService;
  @Autowired
  RuntimeService runtimeService;
  @Autowired
  TaskService taskService;
  //获取流程历史信息的服务类
  @Autowired
  HistoryService historyService;

  @Value("${tienchin.contract.file}")
  String contractFolder;
  SimpleDateFormat sdf = new SimpleDateFormat("/yyyy/MM/dd/");

  @Override
  public AjaxResult uploadContractFile(HttpServletRequest request, MultipartFile file) {
    //上传的文件夹
    String format = sdf.format(new Date());
    String fileDir = contractFolder + format;
    File dir = new File(fileDir);
    if (!dir.exists()){
      //如果文件夹不存在，创建文件夹
      dir.mkdirs();
    }
    //原始文件名
    String originalFilename = file.getOriginalFilename();
    //新的文件名
    String newName = UUID.randomUUID().toString() + "-" + originalFilename;
    try {
      file.transferTo(new File(dir,newName));
      String url = request.getScheme() + "://" + request.getServerName() + ":"
              + request.getServerPort()
              + request.getContextPath()
              + "/tienchin/contract/views"
              + format + newName;
      Map<String,String> resp = new HashMap<>();
      resp.put("url",url);
      resp.put("name",originalFilename);
      return AjaxResult.success(resp);
    } catch (IOException e) {
      throw new RuntimeException(e);
    }
  }

  @Override
  public AjaxResult deleteContractFile(String year, String month, String day, String name) {
    String fileName = contractFolder + File.separator + year
            +File.separator + month + File.separator + day + File.separator + name;
    File file = new File(fileName);
    boolean delete = file.delete();
    return delete ? AjaxResult.success("文件删除成功") : AjaxResult.error("文件删除失败");
  }

  @Override
  public AjaxResult geContractInfoPhone(String phone) {
    List<ContractInfo> list = contractMapper.geContractInfoPhone(phone);
    if (list != null && list.size() > 0) {
      ContractInfo contractInfo = list.get(0);
      return AjaxResult.success(contractInfo);
    } else {
      return AjaxResult.error("手机号码输入错误，客户不存在");
    }
  }

  @Override
  @Transactional
  public AjaxResult addContract(Contract contract) {
    //1.向合同表中添加数据
    //1.1 查询商机 ID 并设置
    QueryWrapper<Business> qw = new QueryWrapper<>();
    qw.lambda().eq(Business::getPhone, contract.getPhone()).orderByDesc(Business::getCreateTime);
    List<Business> list = businessService.list(qw);
    Integer businessId = list.get(0).getBusinessId();
    contract.setBusinessId(businessId);
    //1.2 查询课程价格并设置
    QueryWrapper<Course> cqw = new QueryWrapper<>();
    cqw.lambda().eq(Course::getCourseId, contract.getCourseId());
    Course c = courseService.getOne(cqw);
    contract.setCoursePrice(c.getPrice());
    //1.3 设置通用属性
    contract.setCreateBy(SecurityUtils.getUsername());
    contract.setCreateTime(LocalDateTime.now());
    contract.setDelFlag(0);
    contract.setStatus(TienChinConstants.CONTRACT_UNAPPROVE);
    save(contract);
    //2.启动流程
    //2.1启动流程
    //设置当前过程的处理人
    Map<String,Object> piVars = new HashMap<>();
    piVars.put("currentUser",SecurityUtils.getUsername());
    ProcessInstance processInstance = runtimeService.startProcessInstanceByKey(TienChinConstants.CONTRACT_PROCESS_DEFINITION_ID,piVars);
    Map<String,Object> vars = new HashMap<>();
    vars.put("contractId",contract.getContractId());
    vars.put("approveUser",contract.getApproveUserName());
    vars.put("approveUserId",contract.getApproveUserId());
    //提交后直接由当前用户完成当前任务
    Task task = taskService.createTaskQuery().processInstanceId(processInstance.getId()).singleResult();
    taskService.complete(task.getId(),vars);
    //3.更新合同信息
    contract.setProcessInstanceId(processInstance.getProcessInstanceId());
    updateById(contract);
    return AjaxResult.success("提交成功");
  }

  @Override
  public List<ContractSummary> getUnApproveTask() {
    List<ContractSummary> result = new ArrayList<>();
    //查询当前用户需要处理的任务
    List<Task> list = taskService.createTaskQuery().taskAssignee(SecurityUtils.getUsername()).processDefinitionKey(TienChinConstants.CONTRACT_PROCESS_DEFINITION_ID)
            .active().orderByTaskCreateTime().desc().list();
    for (Task task : list) {
      String taskId = task.getId();
      Integer contractId = (Integer) taskService.getVariable(task.getId(), "contractId");
      String reason = (String) taskService.getVariable(task.getId(), "reason");
      ContractSummary summary = new ContractSummary();
      Contract contract = getById(contractId);
      BeanUtils.copyProperties(contract, summary);
      summary.setTaskId(taskId);
      summary.setReason(reason);
      result.add(summary);
    }
    return result;
  }

  @Override
  public List<ContractSummary> getCommittedTask() {
    List<ContractSummary> result = new ArrayList<>();
    List<Execution> list = runtimeService.createExecutionQuery().variableValueEquals("currentUser", SecurityUtils.getUsername())
            .processDefinitionKey(TienChinConstants.CONTRACT_PROCESS_DEFINITION_ID).list();
    for (Execution execution : list) {
      String eId = execution.getId();
      Integer contractId = (Integer) runtimeService.getVariable(execution.getId(), "contractId");
      String reason = (String) runtimeService.getVariable(execution.getId(), "reason");
      ContractSummary summary = new ContractSummary();
      Contract contract = getById(contractId);
      BeanUtils.copyProperties(contract, summary);
      summary.setTaskId(eId);
      summary.setReason(reason);
      result.add(summary);
    }
    return result;
  }

  @Override
  public AjaxResult getContractById(Integer contractId) {
    Contract contract = getById(contractId);
    return AjaxResult.success(contract);
  }

  @Override
  public AjaxResult showContractPDF(String year, String month, String day, String name) {
    FileInputStream inputStream = null;
    ByteArrayOutputStream baos = null;
    try {
      //word 的文件完整路径
      String docFilePath = contractFolder + File.separator + year + File.separator + month + File.separator + day + File.separator + name;
      String pdfFilePath = docFilePath.replace(".docx",".pdf").replace(".doc",".pdf");
      File pdfFile = new File(pdfFilePath);
      if (!pdfFile.exists()){
        //将word转为pdf
        PdfSaveOptions options = new PdfSaveOptions();
        options.setCompliance(PdfCompliance.PDF_17);
        Document doc = new Document(docFilePath);
        doc.save(pdfFilePath,options);
      }
      inputStream = new FileInputStream(pdfFilePath);
      baos = new ByteArrayOutputStream();
      int len = 0;
      byte[] buf = new byte[1024];
      while ((len = inputStream.read(buf)) != -1){
        baos.write(buf,0,len);
      }
      return AjaxResult.success(Base64.encode(baos.toByteArray()));
    } catch (Exception e) {
      throw new RuntimeException(e);
    }finally {
      if (inputStream != null){
        try {
          inputStream.close();
        } catch (IOException e) {
          throw new RuntimeException(e);
        }
      }
      if (baos != null){
        try {
          baos.close();
        } catch (IOException e) {
          throw new RuntimeException(e);
        }
      }
    }
  }

  @Override
  @Transactional
  public AjaxResult approveOrReject(ContractApproveInfo info) {
    Map<String,Object> vars = new HashMap<>();
    vars.put("approve",info.getApprove());
    vars.put("reason",info.getReason());
    taskService.complete(info.getTaskId(),vars);
    //修改合同表中关于这条合同中的状态
    UpdateWrapper<Contract> updateWrapper = new UpdateWrapper<>();
    if (info.getApprove()){
      updateWrapper.lambda().set(Contract::getStatus,TienChinConstants.CONTRACT_APPROVE).eq(Contract::getContractId,info.getContractId());
    }else {
      updateWrapper.lambda().set(Contract::getStatus,TienChinConstants.CONTRACT_REJECT).eq(Contract::getContractId,info.getContractId());

    }
    update(updateWrapper);
    return AjaxResult.success("审批完成");
  }

  @Override
  public List<ContractSummary> approvedTask() {
    List<ContractSummary> res = new ArrayList<>();
    List<HistoricProcessInstance> list = historyService.createHistoricProcessInstanceQuery()
            .variableValueEquals("currentUser", SecurityUtils.getUsername()).finished().list();
    for (HistoricProcessInstance hpi : list) {
      List<HistoricVariableInstance> list1 = historyService.createHistoricVariableInstanceQuery().processInstanceId(hpi.getId()).list();
      Integer contractId = null;
      String reason = null;
      for (HistoricVariableInstance hvi : list1) {
        if ("contractId".equals(hvi.getVariableName())){
          contractId = (Integer) hvi.getValue();
        } else if ("reason".equals(hvi.getVariableName())) {
          reason = (String) hvi.getValue();
        }
      }
      Contract contract = getById(contractId);
      ContractSummary contractSummary = new ContractSummary();
      BeanUtils.copyProperties(contract,contractSummary);
      contractSummary.setReason(reason);
      res.add(contractSummary);
    }
    return res;
  }

  @Override
  @Transactional
  public AjaxResult updateContract(Contract contract) {
    //1.向合同表中更新数据
    //1.1 设置通用属性
    contract.setUpdateBy(SecurityUtils.getUsername());
    contract.setUpdateTime(LocalDateTime.now());
    contract.setStatus(TienChinConstants.CONTRACT_UNAPPROVE);
    updateById(contract);
    //2.提交流程
    //2.1启动流程
    //设置当前过程的处理人

    Map<String,Object> vars = new HashMap<>();
    vars.put("contractId",contract.getContractId());
    vars.put("approveUser",contract.getApproveUserName());
    vars.put("approveUserId",contract.getApproveUserId());
    vars.put("currentUser",SecurityUtils.getUsername());

    //按照之前的流程id 去完成当前流程中的任务
    Task task = taskService.createTaskQuery().processInstanceId(contract.getProcessInstanceId()).active().singleResult();
    taskService.complete(task.getId(),vars);

    return AjaxResult.success("提交成功");
  }
}
